package advanced;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 学习Java的反射机制
 * <p>
 * 反射reflection: 把Java类中的各种数据结构(方法、属性、构造器、类名）映射成一个个的对象。
 * 利用反射技术可以对一个类进行解刨。
 */
public class L_Reflection {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //三种方式
        //1. 对象.getClass()  由对象获取其原始的类结构信息
        Class clz = new Iphone().getClass();
        //2. 类.class  已知类结构（可拿到）
        clz = Iphone.class;
        //3. Class.forName("包名.类名")  通过定位找到对应的类结构
        clz = Class.forName("advanced.Iphone");

        //创建对象  该方式已经过时了，不推荐
        Iphone iphone = (Iphone) clz.newInstance();
        System.out.println(iphone);

        //第二种方法创建对象
        Iphone iphone1 = (Iphone) clz.getConstructor().newInstance();//调用无参的构造器
        System.out.println(iphone1);
        Iphone iphone2 = (Iphone) clz.getConstructor(String.class).newInstance("kk");
        System.out.println(iphone2);


        //给属性赋值
        Field field = clz.getDeclaredField("name");
        field.setAccessible(true);//如果是私有属性,设置true之后就可以访问,否则会报异常,同时关闭了安全检查,会提高反射速度
        field.set(iphone1, "yeung");
        //使用反射api 调用普通方法
        Method method = clz.getDeclaredMethod("printInfo", null);
        method.invoke(iphone1, null);

    }
}

/**
 * 反射操作泛型(Generic)
 * 泛型在编译完成之后就会被编译器擦除掉
 *
 * 为了通过反射操作这些类型以迎合实际开发的需要,Java就增加了ParameterizedType, GenericArrayType, TypeVariable和WildcardType
 * 几种类型来代表不能被鬼一道class类中国的类型但是有何原始类型齐名的类型
 *
 * 最常用的是: ParameterizedType
 *
 */
class Iphone {
    private String name;

    /**
     * 很多框架都会使用反射调用无参构造器创建对象
     * 因此 一定要养成习惯写无参构造器
     * 否则很多框架可能会报错
     */
    public Iphone() {
    }

    public Iphone(String name) {
        this.name = name;
    }

    public void printInfo() {
        System.out.println("通过反射调用了本方法" + this.name);
    }
}
